home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
intrvews
/
xgrab.lha
/
xgrab
/
grabst
/
levels.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-06
|
10KB
|
368 lines
/**
GRAB Graph Layout and Browser System
Copyright (c) 1986, 1988 Regents of the University of California
Copyright (c) 1989, Tera Computer Company
**/
/* levels.c -- routines to manipulate the level structure of the digraph */
#include "malloc.h"
#include <string.h>
#include "attribute.h"
#include "digraph.h"
#include "debug.h"
#define DUMMY_SHAPE POINT /* default shape for dummy */
#define DUMMY_BRUSH SOLIDB /* default brush for dummy */
#define DUMMY_COLOR BLACK /* default color for dummy */
VERTEX *insert_vertex();
NODE *insert_node();
LEVEL *find_level();
char **dispose_out_edge();
add_level(digraph, members)
DIGRAPH *digraph;
SET *members; /* members of the level */
/* add_level adds a new level to digraph with the vertices in members. */
{
VNO vno; /* each vertex number */
LEVEL *level; /* the new level */
new(level, LEVEL);
Prev_level(level) = NULL;
Next_level(level) = digraph->levels; /* link in at the head */
digraph->levels = level;
if (Next_level(level) != NULL) /* fix previous of next */
{
Prev_level(Next_level(level)) = level;
}
else /* this is the last level */
{
Last_level(digraph) = level;
}
Order(level) = NULL;
Lno(level) = 0; /* don't know level number yet */
Num_cross(level) = -1; /* no crossings calculated yet */
init_set(Members(level));
each_element(members, vno)
loop
/* add a non-dummy member */
add_member(digraph, level, vno, NORMAL);
endloop
} /* add_level */
add_dummy(digraph, new_level, vno, ante_set)
DIGRAPH *digraph;
LEVEL *new_level; /* level to put the dummy on */
VNO vno; /* succedent of the dummy */
SET *ante_set; /* antecedents of the dummy */
/**
add_dummy adds dummy nodes to new_level with succedent vno and antecedents
in ante_set. If vno has no succedents, then vno itself is moved from its
current level to new_level instead of creating dummies.
**/
{
char name[100]; /* name of the dummy */
NODE *dummy_node;
VERTEX *dummy_vertex;
VNO dummy_vno; /* the dummy vno */
VNO from_vno; /* each antecedent of dummy */
int sub_num; /* counter for more than one dummy */
int i;
char **attr;
if (empty(Succ_set(Node(digraph, vno))) &&
equal(Ante_set(Node(digraph, vno)), ante_set))
{
LEVEL *vno_level; /* level vno is on */
/* move to new_level */
vno_level = find_level(digraph, vno); /* get vno's level */
move_member(digraph, vno_level, vno, new_level);
return;
}
/* otherwise create a dummy */
Last_dummy(Member(digraph, vno))++; /* adding another dummy */
sub_num = 0; /* for more than one dummy */
each_element(ante_set, from_vno) /* fix up antecedents */
loop
sprintf(name, "->%s.%d.%d", Name(Node(digraph, vno)),
Last_dummy(Member(digraph, vno)), sub_num++);
/* create the array of (null) attributes */
attr = (char **) malloc(NNodeAttr(digraph) * sizeof(char *));
for (i = 0; i < NNodeAttr(digraph); i++)
{
strsave(attr[i], NULL_STRING);
}
/* create a dummy. */
dummy_vertex = insert_vertex(digraph, name);
dummy_node = insert_node(digraph, dummy_vertex, attr, DUMMY_SHAPE,
DUMMY_BRUSH, DUMMY_COLOR, TRUE, 0, 0, DUMMY);
/**
for multi-graph and two-way edges: All edges between a pair
of nodes follow the same path, including dummy nodes. So
dummy nodes are made wider to support more than one distinct
in and out edge.
**/
Half_width(dummy_node) += EDGE_GAP *
max_edges(Node(digraph, from_vno),
Node(digraph, vno)) / 2;
dummy_vno = Vno(dummy_node);
remove_element(Succ_set(Node(digraph, from_vno)), vno);
add_element(Succ_set(Node(digraph, from_vno)), dummy_vno);
add_element(Ante_set(Node(digraph, dummy_vno)), from_vno);
add_element(Succ_set(Node(digraph, dummy_vno)), vno);
remove_element(Ante_set(Node(digraph, vno)), from_vno);
/* shorten span */
add_element(Ante_set(Node(digraph, vno)), dummy_vno);
/* now add a dummy member */
add_member(digraph, new_level, dummy_vno, DUMMY);
if (debug)
{
printf("\nadd_dummy: created dummy '%s'\n",
Name(Node(digraph, dummy_vno)));
printf(" Succedents: ");
print_set(digraph, Succ_set(Node(digraph, dummy_vno)));
printf("\n Antecedents: ");
print_set(digraph, Ante_set(Node(digraph, dummy_vno)));
printf("\n");
}
endloop
} /* add_dummy */
add_member(digraph, level, vno, status)
DIGRAPH *digraph;
LEVEL *level; /* level for new member */
VNO vno; /* vno of new member */
STATUS status; /* status of new member */
/* add_member adds a new member to level. */
{
MEMBER *member; /* the new member */
member = Member(digraph, vno);
Next_member(member) = Order(level);
Order(level) = member;
Prev_member(member) = NULL;
if (Next_member(member) != NULL)
{
Prev_member(Next_member(member)) = member;
}
Status(member) = status;
Bc(member, UP) = Bc(member, DOWN) = NO_BC;
Level_no(member) = Lno(level);
add_element(Members(level), vno);
} /* add_member */
remove_member(digraph, level, vno)
DIGRAPH *digraph;
LEVEL *level;
VNO vno;
/**
remove_member removes the member for vno from level. If vno is not
a member of level, an error occurs.
**/
{
MEMBER *member;
member = Member(digraph, vno);
if (Prev_member(member) == NULL) /* new head */
{
Order(level) = Next_member(member);
}
else
{
Next_member(Prev_member(member)) = Next_member(member);
}
if (Next_member(member) != NULL)
{
Prev_member(Next_member(member)) = Prev_member(member);
}
Next_member(member) = Prev_member(member) = NULL;
remove_element(Members(level), vno);
} /* remove_member */
move_member(digraph, from_level, vno, to_level)
DIGRAPH *digraph;
LEVEL *from_level;
VNO vno;
LEVEL *to_level;
/* move_member moves vno from from_level to to_level. */
{
MEMBER *member;
member = Member(digraph, vno);
remove_member(digraph, from_level, vno); /* remove from previous level */
add_member(digraph, to_level, vno, Status(member));
} /* move_member */
LEVEL *find_level(digraph, vno)
DIGRAPH *digraph;
VNO vno;
/**
find_level finds the level in which vno is a member in digraph. If there
is no such level, NULL is returned.
**/
{
LEVEL *level; /* each level */
if (debug)
{
printf("\nfind_level: looking for level of '%s'\n",
Name(Node(digraph, vno)));
}
each_level(digraph, level)
loop
if (in(Members(level), vno))
{
return(level);
}
endloop
return(NULL);
} /* find_level */
remove_long_spans(digraph)
DIGRAPH *digraph;
/**
remove_long_spans follows dummy edges from NORMAL node to NORMAL node and
removes the long span from the appropriate successor and ancestor sets.
**/
{
NODE *node, *next;
VNO vno;
NODE *next_dummy();
each_node(digraph, node)
loop
if (Status(node) != NORMAL)
{
continue;
}
each_element(Succ_set(node), vno)
loop
next = Node(digraph, vno);
if (!Is_dummy(next))
{
continue;
}
while (Is_dummy(next))
{
next = next_dummy(digraph, next);
}
if (Status(next) != NORMAL)
{
continue;
}
/**
next is now the next NORMAL node after a series
of dummy nodes
**/
remove_element(Succ_set(node), Vno(next));
remove_element(Ante_set(next), Vno(node));
endloop
endloop
} /* remove_long_spans */
OUTEDGE *get_edge();
INEDGE *get_in_edge();
reverse_edge(digraph, vno, root_vno, ord)
DIGRAPH *digraph;
VNO vno; /* last vno before cycle */
VNO root_vno; /* vertex # of successor to vno, causing cycle */
int ord; /* ordinality of the edge */
/**
reverse-edge removes an edge and its associated set members, and adds
a new edge, with the same attributes, going in the opposite direction.
**/
{
NODE *node, *root_node;
int errval; /* 0 if insert_edge successful */
NODE *realnode, *realroot;
int realord;
INEDGE *inedge;
OUTEDGE *outedge;
BRUSH brush;
COLOR color;
char **attr;
BOOL reverse;
node = Node(digraph, vno);
root_node = Node(digraph, root_vno);
if (Is_dummy(node) || Is_dummy(root_node))
{
return;
}
outedge = get_edge(digraph, node, root_node, ord);
inedge = get_in_edge(digraph, node, root_node, ord);
/**
nodes could be coalescers, so we need to get the real
endpoints of the edge.
**/
realroot = Node(digraph, To_vno(outedge));
realnode = Node(digraph, From_vno(inedge));
reverse = !Edge_reversed(outedge);
realord = Ord(outedge);
if (debug)
{
printf("Reversing Edge: (%s, %s)\n", Name(node), Name(root_node));
}
/**
note: normally, you'd have to check if this were the last edge
between the two nodes before you removed the link. But we know
that all edges between two nodes go in the same direction, so if
we're reversing this edge, we're reversing all the edges from node
to root_node, and we can safely remove the link.
**/
remove_link(node, root_node);
attr = dispose_out_edge(realnode, Vno(realroot), realord, &brush,
&color);
dispose_in_edge(realroot, Vno(realnode), realord);
errval = insert_edge(digraph, Vno(realroot), Vno(realnode), attr, brush,
color);
realord = max_edges(realroot, realnode);
/* ord has now changed */
if (errval != 0)
{
PrintError("reverse_edge: illegal vertex number");
}
else
{
outedge = get_edge(digraph, realroot, realnode, realord);
inedge = get_in_edge(digraph, realroot, realnode, realord);
Edge_reversed(outedge) = reverse;
Edge_reversed(inedge) = reverse;
}
} /* reverse_edge */